package service

import (
	"errors"
	"fmt"
	"gorm.io/gorm"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"tdy-backend/app/core/service"
	"tdy-backend/app/panoramic/dto"
	"tdy-backend/app/panoramic/model"
	wsService "tdy-backend/app/ws/service"
	"tdy-backend/global"
	"tdy-backend/pkg/paginator"
	"tdy-backend/pkg/storage"
	"tdy-backend/pkg/storage/oss"
	"tdy-backend/pkg/storage/qiniu"
	"tdy-backend/utils"
)

type MaterialService struct {
	service.BaseService
}

//新增素材
func (o *MaterialService) Add(param *dto.MaterialCommitDto) error {
	materials := []model.Material{}
	for _, item := range *param.SubParam {
		mid := strings.Split(item.Panoramic, "/")
		mid[len(mid)-1] = "panoramic/"
		path := strings.Join(mid, "/")
		materialItem := model.Material{
			Title:     item.Title,
			Status:    1,
			Path:      path,
			Panoramic: item.Panoramic,
			Kind:      param.Kind,
			MemberId:  o.MemberInfo.ID,
			Size:      item.Size,
		}
		//设置金额纬度
		lat, lng, alt, err := utils.ReadExifGps(item.Panoramic)
		if err == nil {
			materialItem.Lat = lat
			materialItem.Lng = lng
			materialItem.Alt = alt
		}
		materials = append(materials, materialItem)
	}
	materialCount := len(*param.SubParam)
	if materialCount <= 0 {
		return errors.New("文件素材不能为空")
	}
	db := o.DB
	create := db.Create(&materials)
	if create.Error != nil {
		return errors.New("素材创建失败")
	}

	queue := make(chan []string, materialCount)
	for _, item := range materials {
		queue <- []string{
			fmt.Sprintf("%d", item.ID),
			fmt.Sprintf("%d", item.Kind),
			item.Panoramic,
			param.Key,
			param.UniqueKey,
		}
	}
	close(queue)
	go o._addReader(queue)
	return nil
}

//新增消费者
func (o *MaterialService) _addReader(p chan []string) {
	for s := range p {
		id, _ := strconv.ParseUint(s[0], 10, 64)
		kind, _ := strconv.ParseInt(s[1], 10, 64)
		o._convert(id, kind, s[2], s[3], s[4])
	}
}

//转换全景
func (o *MaterialService) _convert(id uint64, kind int64, path string, key string, uniqueKey string) bool {
	logger := global.TYD_LOGGER
	wsMessageService := wsService.MessageService{}
	updateParam := model.Material{Status: 2}
	o.SetMaterialData(id, &updateParam)
	var configName string
	var fragmentFile []string
	//解析路径
	midData := strings.Split(path, "/")
	//uniqueKey := midData[len(midData)-2]
	midData[len(midData)-1] = "panoramic"
	panoramicPath := strings.Join(midData, "/")
	switch kind {
	case 1:
		configName = "tdy-normal.config"

		filenameTemplateName := []string{"pano_b.jpg", "pano_d.jpg", "pano_f.jpg", "pano_l.jpg", "pano_r.jpg", "pano_u.jpg", "preview.jpg", "thumb.jpg"}
		for _, s := range filenameTemplateName {
			fragmentFile = append(fragmentFile, panoramicPath+"/"+s)
		}
	case 2:
		configName = "tdy-hd.config"
		fragmentFile, _ = utils.GetAllFile(panoramicPath)
	default:
		logger.Error("kind出错")

		wsMessageService.Send(uniqueKey, map[string]interface{}{"Status": "Error", "Key": key})
		return false
	}
	cmd := exec.Command("tdy/tdytool-mac", "makepano", path, "-config="+configName)
	out, err := cmd.Output()
	if err != nil {
		wsMessageService.Send(uniqueKey, map[string]interface{}{"Status": "Error", "Key": key})
		return false
	}
	if !strings.Contains(string(out), "making images...") {
		wsMessageService.Send(uniqueKey, map[string]interface{}{"Status": "Error", "Key": key})
		return false
	}

	storageType := global.TYD_CONFIG.GetString("file.storage")
	if storageType != "File" {

		switch storageType {
		case "Qiniu":
			uploadInstance := qiniu.NewQiniu()
			for _, file := range fragmentFile {
				uploadInstance.Upload(file, file)
			}
		case "Oss":
			uploadInstance := oss.NewOss()
			for _, file := range fragmentFile {
				uploadInstance.Upload(file, file)
			}
		default:
			logger.Error("未知类型")
		}

	}
	if kind == 2 {
		info := model.MaterialInfo{}
		tileSize, levels, resolution, _ := o._parseResult(string(out))
		info.TileSize = tileSize
		info.Levels = levels
		fmt.Printf("切片内容是：%v", resolution)
		info.Resolution = strings.Join(resolution, ",")
		updateParam.Info = &info
	}

	updateParam.Status = 3

	material, _ := o.SetMaterialData(id, &updateParam)
	wsMessageService.Send(uniqueKey, map[string]interface{}{"Status": "Success", "Key": key, "Row": material})
	return true
}

//解析转码返回的结果
func (o *MaterialService) _parseResult(result string) (tileSize int, levels int, resolution []string, err error) {
	r, _ := regexp.Compile(`tilesize=(\d)* levels=(\d)*(.*)?(\d*)x(\d*)`)
	rs := r.FindAllString(result, -1)
	if len(rs) > 0 {
		tmpData := strings.Split(rs[0], "-")
		for _, v := range tmpData {
			mid := strings.TrimSpace(v)
			str := strings.Split(mid, " ")
			for _, vo := range str {
				if strings.Contains(vo, "tilesize") {
					coreParam := strings.Split(vo, "=")
					i, _ := strconv.Atoi(coreParam[1])
					tileSize = i

				}
				if strings.Contains(vo, "levels") {
					coreParam := strings.Split(vo, "=")
					i, _ := strconv.Atoi(coreParam[1])
					levels = i
				}
				if strings.Contains(vo, "x") {
					coreParam := strings.Split(vo, "x")
					resolution = utils.Push(resolution, coreParam[0])
				}

			}
		}
		resolution = utils.Push(resolution, strconv.Itoa(tileSize))

	}
	return
}

//设置状态
func (o *MaterialService) SetMaterialData(id uint64, param *model.Material) (*model.Material, error) {
	logger := global.TYD_LOGGER
	material := model.Material{}
	db := global.TYD_DB
	materialInfo := db.Where("id=?", id).First(&material)

	if errors.Is(materialInfo.Error, gorm.ErrRecordNotFound) {
		logger.Error("素材数据不存在")
		return nil, materialInfo.Error
	}
	updateData := map[string]interface{}{}
	if param.Status > 0 {
		updateData["status"] = param.Status
	}
	if param.Info != nil {
		updateData["info"] = param.Info
	}
	save := db.Model(&material).Updates(updateData)
	if save.Error != nil {
		logger.Error("状态更新失败")
		return nil, save.Error
	}
	material.ThumbPreview = storage.GetUrl(material.Path + "thumb.jpg")
	return &material, nil
}

// 素材更新
func (o *MaterialService) Edit(param *dto.MaterialEditDto) error {
	material := model.Material{}
	db := o.DB
	materialInfo := db.Where("id = ?", param.ID).Where("member_id=?", o.MemberInfo.ID).First(&material)
	if errors.Is(materialInfo.Error, gorm.ErrRecordNotFound) {
		return errors.New("作品数据不存在")
	}
	material.Title = param.Title
	save := db.Select("title").Save(&material)

	if save.Error != nil {
		return save.Error
	}
	return nil

}

//删除素材
func (o *MaterialService) Delete(param *dto.MaterialDeleteDto) error {
	materials := []model.Material{}
	db := o.DB
	materialInfo := db.Where("id IN ?", param.Ids).Where("member_id=?", o.MemberInfo.ID).Find(&materials)
	if materialInfo.RowsAffected == 0 {
		return errors.New("素材数据不存在")
	}
	db.Delete(&materials)
	return nil
}

//分页列表
func (o MaterialService) ListForPage(param *dto.MaterialListDto) *paginator.Pagination {
	//logger := global.TYD_LOGGER
	db := o.DB.Model(&model.Material{})
	materialList := []model.Material{}

	if param.Keyword != "" {
		db = db.Where("title like ?", "%"+param.Keyword+"%")
	}
	db = db.Where("member_id=?", o.MemberInfo.ID).Where("kind=?", param.Kind)

	var total int64
	db.Count(&total)
	db.Scopes(paginator.Paginate(&param.PageParam)).Order("id desc").Find(&materialList)
	result := &paginator.Pagination{}
	result.Page = param.Page
	result.PageSize = param.PageSize
	result.Total = total
	for k, item := range materialList {
		materialList[k].ThumbPreview = storage.GetUrl(item.Path + "thumb.jpg")
	}
	result.Data = materialList

	return result
}

func (o *MaterialService) GetMaterialMoreRow(materialIds []uint) (*[]model.Material, error) {
	materials := []model.Material{}
	db := global.TYD_DB
	material := model.Material{}
	for _, id := range materialIds {
		db.Where("id =?", id).First(&material)
		materials = append(materials, material)
	}
	//materialsInfo := db.Where("id IN ?", materialIds).Find(&materials)
	//if materialsInfo.RowsAffected == 0 {
	//	return nil, errors.New("素材数据不存在")
	//}
	if len(materials) == 0 {
		return nil, errors.New("素材数据不存在")
	}
	return &materials, nil
}

func (o MaterialService) GetMaterialOneRow(materialId uint64) (*model.Material, error) {

	material := model.Material{}
	db := o.DB
	materialInfo := db.Where("id=?", materialId).Where("member_id=?", o.MemberInfo.ID).First(&material)
	if errors.Is(materialInfo.Error, gorm.ErrRecordNotFound) {
		return nil, errors.New("作品数据不存在")
	}
	material.PathPreview = storage.GetUrl(material.Path)
	return &material, nil
}
